import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'

/**
 * 日期格式化工具函数
 */

export type DateInput = Date | string | number

/**
 * 格式化日期
 * @param date 日期（Date对象、时间戳、日期字符串）
 * @param format 格式化模板
 * @returns 格式化后的日期字符串
 */
export const formatDate = (date: DateInput, format: string = 'YYYY-MM-DD HH:mm:ss'): string => {
  if (!date) return ''

  const d = new Date(date)

  // 检查日期是否有效
  if (Number.isNaN(d.getTime())) {
    console.warn('Invalid date:', date)
    return ''
  }

  const year = d.getFullYear()
  const month = d.getMonth() + 1
  const day = d.getDate()
  const hours = d.getHours()
  const minutes = d.getMinutes()
  const seconds = d.getSeconds()
  const week = d.getDay()

  const weekMap: Record<number, string> = {
    0: '日',
    1: '一',
    2: '二',
    3: '三',
    4: '四',
    5: '五',
    6: '六',
  }

  const pad = (num: number): string => num.toString().padStart(2, '0')

  return format
    .replace(/YYYY/g, year.toString())
    .replace(/YY/g, year.toString().slice(-2))
    .replace(/MM/g, pad(month))
    .replace(/M/g, month.toString())
    .replace(/DD/g, pad(day))
    .replace(/D/g, day.toString())
    .replace(/HH/g, pad(hours))
    .replace(/H/g, hours.toString())
    .replace(/mm/g, pad(minutes))
    .replace(/m/g, minutes.toString())
    .replace(/ss/g, pad(seconds))
    .replace(/s/g, seconds.toString())
    .replace(/W/g, weekMap[week])
}

/**
 * 格式化为相对时间（多久之前）
 * @param date 日期
 * @returns 相对时间描述
 */
export const formatRelativeTime = (date: DateInput): string => {
  if (!date) return ''

  const d = new Date(date)
  const now = new Date()
  const diff = now.getTime() - d.getTime()

  // 无效日期
  if (Number.isNaN(d.getTime())) return ''

  const seconds = Math.floor(diff / 1000)
  const minutes = Math.floor(seconds / 60)
  const hours = Math.floor(minutes / 60)
  const days = Math.floor(hours / 24)
  const months = Math.floor(days / 30)
  const years = Math.floor(days / 365)

  if (seconds < 60) return '刚刚'
  if (minutes < 60) return `${minutes}分钟前`
  if (hours < 24) return `${hours}小时前`
  if (days < 30) return `${days}天前`
  if (months < 12) return `${months}个月前`
  return `${years}年前`
}

/**
 * 格式化为友好的日期显示
 * @param date 日期
 * @param showTime 是否显示时间
 * @returns 友好的日期字符串
 */
export const formatFriendlyDate = (date: DateInput, showTime: boolean = true): string => {
  if (!date) return ''

  const d = new Date(date)
  const now = new Date()

  // 无效日期
  if (Number.isNaN(d.getTime())) return ''

  const isToday = isSameDay(d, now)
  const isYesterday = isSameDay(d, new Date(now.getTime() - 24 * 60 * 60 * 1000))
  const isTomorrow = isSameDay(d, new Date(now.getTime() + 24 * 60 * 60 * 1000))
  const isThisYear = d.getFullYear() === now.getFullYear()

  const timeStr = showTime ? ` ${formatDate(d, 'HH:mm')}` : ''

  if (isToday) return `今天${timeStr}`
  if (isYesterday) return `昨天${timeStr}`
  if (isTomorrow) return `明天${timeStr}`
  if (isThisYear) return `${formatDate(d, 'MM-DD')}${timeStr}`
  return `${formatDate(d, 'YYYY-MM-DD')}${timeStr}`
}

/**
 * 判断是否为同一天
 * @param date1 日期1
 * @param date2 日期2
 * @returns 是否为同一天
 */
export const isSameDay = (date1: DateInput, date2: DateInput): boolean => {
  const d1 = new Date(date1)
  const d2 = new Date(date2)

  return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate()
}

/**
 * 获取日期范围描述
 * @param startDate 开始日期
 * @param endDate 结束日期
 * @returns 日期范围字符串
 */
export const formatDateRange = (startDate: DateInput, endDate: DateInput): string => {
  if (!startDate || !endDate) return ''

  const start = formatDate(startDate, 'YYYY-MM-DD')
  const end = formatDate(endDate, 'YYYY-MM-DD')

  if (start === end) return start
  return `${start} 至 ${end}`
}

/**
 * 获取时间段描述
 * @param date 日期
 * @returns 时间段描述（上午、下午、晚上）
 */
export const getTimePeriod = (date: DateInput = new Date()): string => {
  const d = new Date(date)
  const hours = d.getHours()

  if (hours >= 6 && hours < 12) return '上午'
  if (hours >= 12 && hours < 18) return '下午'
  return '晚上'
}

/**
 * 格式化预约时间
 * @param date 日期
 * @returns 预约时间描述
 */
export const formatAppointmentTime = (date: DateInput): string => {
  if (!date) return ''

  const d = new Date(date)
  const period = getTimePeriod(d)
  const friendly = formatFriendlyDate(d, false)
  const time = formatDate(d, 'HH:mm')

  return `${friendly} ${period} ${time}`
}

/**
 * 计算两个日期之间的天数差
 * @param date1 日期1
 * @param date2 日期2
 * @returns 天数差
 */
export const daysBetween = (date1: DateInput, date2: DateInput): number => {
  const d1 = new Date(date1)
  const d2 = new Date(date2)

  const diff = Math.abs(d2.getTime() - d1.getTime())
  return Math.floor(diff / (1000 * 60 * 60 * 24))
}

/**
 * 获取本周的开始日期（周一）
 * @param date 参考日期
 * @returns 本周开始日期
 */
export const getWeekStart = (date: DateInput = new Date()): Date => {
  const d = new Date(date)
  const day = d.getDay()
  const diff = d.getDate() - day + (day === 0 ? -6 : 1) // 调整为周一
  return new Date(d.setDate(diff))
}

/**
 * 获取本周的结束日期（周日）
 * @param date 参考日期
 * @returns 本周结束日期
 */
export const getWeekEnd = (date: DateInput = new Date()): Date => {
  const start = getWeekStart(date)
  return new Date(start.getTime() + 6 * 24 * 60 * 60 * 1000)
}

/**
 * 获取本月的开始日期
 * @param date 参考日期
 * @returns 本月开始日期
 */
export const getMonthStart = (date: DateInput = new Date()): Date => {
  const d = new Date(date)
  return new Date(d.getFullYear(), d.getMonth(), 1)
}

/**
 * 获取本月的结束日期
 * @param date 参考日期
 * @returns 本月结束日期
 */
export const getMonthEnd = (date: DateInput = new Date()): Date => {
  const d = new Date(date)
  return new Date(d.getFullYear(), d.getMonth() + 1, 0)
}

/**
 * 判断是否为过期日期
 * @param date 日期
 * @returns 是否过期
 */
export const isExpired = (date: DateInput): boolean => {
  const d = new Date(date)
  const now = new Date()
  return d.getTime() < now.getTime()
}

/**
 * 判断是否为今天
 * @param date 日期
 * @returns 是否为今天
 */
export const isToday = (date: DateInput): boolean => {
  return isSameDay(date, new Date())
}

// 启用自定义解析格式插件
dayjs.extend(customParseFormat)

/**
 * 将时间段字符串转换为时间戳数组
 * @param dateTimeString 时间段字符串，格式：'2025-10-12 09:00-10:00'
 * @returns 时间戳数组 [开始时间戳, 结束时间戳] 或 null（解析失败时）
 */
export const parseTimeRangeToTimestamps = (dateTimeString: string): [number, number] | undefined => {
  try {
    // 分割日期和时间段
    const parts = dateTimeString.split(' ')
    if (parts.length !== 2) {
      console.error('时间格式错误：缺少日期或时间段')
      return undefined
    }

    const [datePart, timePart] = parts

    // 分割开始时间和结束时间
    const times = timePart.split('-')
    if (times.length !== 2) {
      console.error('时间格式错误：时间段格式不正确')
      return undefined
    }

    const [startTime, endTime] = times

    // 组合完整的开始时间和结束时间
    const startDateTime = `${datePart} ${startTime}`
    const endDateTime = `${datePart} ${endTime}`

    // 转换为时间戳（秒级，10位）
    const startTimestamp = Math.floor(dayjs(startDateTime, 'YYYY-MM-DD HH:mm').valueOf() / 1000)
    const endTimestamp = Math.floor(dayjs(endDateTime, 'YYYY-MM-DD HH:mm').valueOf() / 1000)

    // 验证时间戳是否有效
    if (Number.isNaN(startTimestamp) || Number.isNaN(endTimestamp)) {
      console.error('时间解析失败：无效的时间戳')
      return undefined
    }

    // 验证结束时间是否大于开始时间
    if (endTimestamp <= startTimestamp) {
      console.error('时间范围错误：结束时间必须大于开始时间')
      return undefined
    }

    return [startTimestamp, endTimestamp]
  } catch (error) {
    console.error('解析时间范围时出错:', error)
    return undefined
  }
}

export default {
  formatDate,
  formatRelativeTime,
  formatFriendlyDate,
  formatDateRange,
  formatAppointmentTime,
  isSameDay,
  isToday,
  getTimePeriod,
  daysBetween,
  getWeekStart,
  getWeekEnd,
  getMonthStart,
  getMonthEnd,
  isExpired,
}
